/*
    This file is part of MOOPerformanceAssessment.

    MOOPerformanceAssessment is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    MOOPerformanceAssessment is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MOOPerformanceAssessment; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Authors: Thomas Voß, 2007
    Contact: thomas.voss.bochum@googlemail.com
*/

#include "../include/IBinaryQualityIndicator.h"
#include "../include/IDataSetReader.h"
#include "../include/IFileNameAssembler.h"
#include "../include/IPostProcessor.h"
#include "../include/IStatisticalSignificanceTest.h"
#include "../include/IUnaryQualityIndicator.h"
#include "../include/MOOPerformanceAssessmentConfig.h"
#include "../include/MOOPerformanceAssessmentFunctional.h"
#include "../include/MOOPerformanceAssessmentGlobal.h"
#include "../include/MOOPerformanceAssessment.h"

#include <Logger.h>
#include <impl/FileHandler.h>
#include <impl/StreamHandler.h>
#include <impl/DefaultFormatter.h>

#include <QString>
#include <QFile>

#include <iostream>

MOOPerformanceAssessment::MOOPerformanceAssessment()
{
    logging::FileHandler * fileHandler = new logging::FileHandler();
    fileHandler->open( "log.txt" );
    fileHandler->setFormatter( new logging::DefaultFormatter() );

    logging::StreamHandler<std::ostream> * streamHandler = new logging::StreamHandler<std::ostream>( std::cout );
    streamHandler->setFormatter( new logging::DefaultFormatter() );

    m_logger = logging::Logger::getLogger( "MOOPerformanceAssessment" );
    m_logger->addHandler( fileHandler );
    m_logger->addHandler( streamHandler );
}

void MOOPerformanceAssessment::run()
{
    if( CHECK_NULL( m_config.m_dataSetReader ) || CHECK_NULL( m_config.m_fileNameAssembler ) )
	return;
	
    m_logger->info( "Performance Assessment started" );
    m_logger->info( m_config.monitor() );

    char buffer[1024];

    unsigned i, j, k, l, m;
    
    std::vector<PointSet> referenceDataSets;
    std::vector<std::vector<std::vector<PointSet> > > algorithmData;
    std::vector<std::vector<std::vector<std::vector<double> > > > indicatorValues( m_config.m_functions.size(),
										   std::vector<std::vector<std::vector<double> > >( m_config.m_algorithms.size(),
																    std::vector<std::vector<double > >( m_config.m_trials, 
																					std::vector<double>( m_config.m_vIndicators.size(), 0 ) ) ) );

    std::vector<std::vector<std::vector<std::vector<double> > > > significances( m_config.m_functions.size() );
    
    for( i = 0; i < m_config.m_functions.size(); i++ )
	{
	    std::vector<std::vector<PointSet> > data( m_config.m_algorithms.size() );
	    for( j = 0; j < m_config.m_algorithms.size(); j++ )
		{
		    QString uri( "%1/%2" );
		    uri = uri.arg( m_config.m_dataDir ).arg ( (*m_config.m_fileNameAssembler)( m_config.m_algorithms.at( j ),
											       m_config.m_functions.at( i ),
											       m_config.m_trials,
											       m_config.m_generations		
											       ) );		    		    
		    QFile file( uri );
		    file.open(QIODevice::ReadOnly | QIODevice::Text);
		    data[j] = (*m_config.m_dataSetReader)( &file, m_config.m_trials, m_config.m_noObjectives );
		}
	    
	    // Build reference data set for function f_i.
	    PointSet referenceDataSet = merge( data ); 
	    sprintf( buffer, "Number of points in reference data set: %d", referenceDataSet.size() );
	    m_logger->info( buffer );
	    filter( referenceDataSet ); normalize( referenceDataSet, m_config.m_referencePoint );
	    sprintf( buffer, "Number of points in reference data set: %d", referenceDataSet.size() );
	    m_logger->info( buffer );

	    referenceDataSets.push_back( referenceDataSet );

	    // Raw objective vector data read - normalize data sets.
	    for( j = 0; j < data.size(); j++ )
		for( k = 0; k < data[j].size(); k++ )
		    normalize( data[j][k], m_config.m_referencePoint );

	    algorithmData.push_back( data );

	    // Calculating indicator values
	    for( j = 0; j < m_config.m_algorithms.size(); j++ ) 		// algorithms
		if( data[j].size() == m_config.m_trials )
		    for( k = 0; k < m_config.m_trials; k++ )       		// trials
			for( l = 0; l < m_config.m_vIndicators.size(); l++ ) 	// indicators
			    indicatorValues[i][j][k][l] = (*m_config.m_vIndicators.at( l ))( referenceDataSet, data[j][k] );
		else
		    {
			sprintf( buffer, 
				 "DataSet for algorithm %s only contains %d trials.", 
				 qPrintable( m_config.m_algorithms.at( j ) ), 
				 data[j].size()
				 );
			m_logger->severe( buffer );
		    }
	    
	    // Performing Statistical Verification
	    for( j = 0; j < m_config.m_vSignificanceTests.size(); j++ )
		significances[i].push_back( (*m_config.m_vSignificanceTests.at( j ))( indicatorValues[i], m_config ) );
	}

    // Running the post-processors.
    for( i = 0; i < m_config.m_vPostProcessors.size(); i++ )
	{
	    (*m_config.m_vPostProcessors.at( i ))( referenceDataSets,
						   algorithmData,
						   indicatorValues,
						   significances,
						   m_config
						   );
	}	
    m_logger->info( "Performance Assessment finished." );
}
